feat(core): Export a reusable function to add tracing headers#20076
feat(core): Export a reusable function to add tracing headers#20076
Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Core
Deps
Other
Bug Fixes 🐛Core
Other
Internal Changes 🔧Core
Deps
Other
🤖 This preview updates automatically when you update the PR. |
size-limit report 📦
|
node-overhead report 🧳Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.
|
| type PolymorphicRequestHeaders = | ||
| | Record<string, string | undefined> | ||
| | Array<[string, string]> | ||
| | Iterable<Iterable<string>> |
There was a problem hiding this comment.
Accepted Iterable type lacks runtime handling in function
Low Severity
The new Iterable<Iterable<string>> variant was added to PolymorphicRequestHeaders, which is used as the type for fetchOptionsObj.headers. However, the function body only handles Headers instances (via isHeaders), arrays (via Array.isArray), and plain objects (the else branch). A non-array, non-Headers iterable (e.g. a Map) would silently fall into the else branch, where in operator checks and object spread would not correctly process the iterable's entries, producing malformed headers. Since this function is now exported for cross-package use, the type promises broader acceptance than the implementation supports.
Additional Locations (1)
There was a problem hiding this comment.
This type is needed for Cloudflare headers. I've added a test to also check for that case.
d9322e7 to
1622527
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: feat PR lacks integration or E2E test
- Added a Node.js integration test that demonstrates cross-package usage of getTracingHeadersForFetchRequest, validating that the function correctly generates tracing headers when imported from @sentry/core.
Or push these changes by commenting:
@cursor push 7c341385d0
Preview (7c341385d0)
diff --git a/dev-packages/node-integration-tests/suites/public-api/getTracingHeadersForFetchRequest/basic-usage/scenario.ts b/dev-packages/node-integration-tests/suites/public-api/getTracingHeadersForFetchRequest/basic-usage/scenario.ts
new file mode 100644
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/public-api/getTracingHeadersForFetchRequest/basic-usage/scenario.ts
@@ -1,0 +1,30 @@
+import * as Sentry from '@sentry/node';
+import { getTracingHeadersForFetchRequest } from '@sentry/core';
+import { loggingTransport } from '@sentry-internal/node-integration-tests';
+
+Sentry.init({
+ dsn: 'https://public@dsn.ingest.sentry.io/1337',
+ tracesSampleRate: 1.0,
+ transport: loggingTransport,
+});
+
+Sentry.startSpan({ name: 'test-span' }, () => {
+ const headers = getTracingHeadersForFetchRequest('https://example.com/api', {});
+
+ if (!headers || typeof headers !== 'object' || Array.isArray(headers)) {
+ throw new Error('getTracingHeadersForFetchRequest returned invalid headers');
+ }
+
+ const sentryTrace = 'sentry-trace' in headers ? headers['sentry-trace'] : undefined;
+ const baggage = 'baggage' in headers ? headers.baggage : undefined;
+
+ if (!sentryTrace || typeof sentryTrace !== 'string' || !sentryTrace.match(/^[0-9a-f]{32}-[0-9a-f]{16}-[01]$/)) {
+ throw new Error('sentry-trace header is invalid or missing');
+ }
+
+ if (!baggage || typeof baggage !== 'string' || !baggage.includes('sentry-')) {
+ throw new Error('baggage header is invalid or missing');
+ }
+
+ Sentry.captureMessage('test message');
+});
diff --git a/dev-packages/node-integration-tests/suites/public-api/getTracingHeadersForFetchRequest/basic-usage/test.ts b/dev-packages/node-integration-tests/suites/public-api/getTracingHeadersForFetchRequest/basic-usage/test.ts
new file mode 100644
--- /dev/null
+++ b/dev-packages/node-integration-tests/suites/public-api/getTracingHeadersForFetchRequest/basic-usage/test.ts
@@ -1,0 +1,17 @@
+import { afterAll, test } from 'vitest';
+import { cleanupChildProcesses, createRunner } from '../../../../utils/runner';
+
+afterAll(() => {
+ cleanupChildProcesses();
+});
+
+test('should generate tracing headers for fetch request', async () => {
+ await createRunner(__dirname, 'scenario.ts')
+ .expect({
+ event: {
+ message: 'test message',
+ },
+ })
+ .start()
+ .completed();
+});This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
|
q: IIC you want to use this in Cloudflare afterwards? I think we have serveral conventions for internal functions but lately we've been making use of an |
|
Yes for now only for Cloudflare, but in theory this can be then used for other instrumentations then. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8100e43. Configure here.
| // eslint-disable-next-line complexity -- yup it's this complicated :( | ||
| export function _addTracingHeadersToFetchRequest( | ||
| request: string | Request, | ||
| export function _INTERAL_getTracingHeadersForFetchRequest( |
There was a problem hiding this comment.
Typo in exported function name: INTERAL vs INTERNAL
High Severity
The function is named _INTERAL_getTracingHeadersForFetchRequest — missing the "N" in "INTERNAL". The PR discussion explicitly agreed to use the _INTERNAL_ prefix to match the project's established convention (e.g. _INTERNAL_captureLog, _INTERNAL_captureMetric, etc.). Once this ships, fixing the typo would be a breaking change for any consumer already importing it.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8100e43. Configure here.
| // Therefore: | ||
| // eslint-disable-next-line deprecation/deprecation | ||
| export { instrumentFetchRequest } from './fetch'; | ||
| export { instrumentFetchRequest, _INTERAL_getTracingHeadersForFetchRequest } from './fetch'; |
There was a problem hiding this comment.
Bug: The newly exported function _INTERAL_getTracingHeadersForFetchRequest has a typo. The standard prefix is _INTERNAL_, and this will become a breaking change to fix later.
Severity: MEDIUM
Suggested Fix
Rename the function from _INTERAL_getTracingHeadersForFetchRequest to _INTERNAL_getTracingHeadersForFetchRequest everywhere it appears, including the definition, call sites, tests, and the export statement in packages/core/src/index.ts.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/core/src/index.ts#L145
Potential issue: The function `_INTERAL_getTracingHeadersForFetchRequest` is named with
a typo, missing the second 'N' in 'INTERNAL'. This typo is present in its definition,
internal call sites, and its public export from `packages/core/src/index.ts`. The
established convention in the codebase is to use the `_INTERNAL_` prefix for such
exports. Since this function is part of the public API for cross-package use, external
consumers will adopt the misspelled name. Correcting it in the future will introduce a
breaking change, causing import failures for all consumers.
Did we get this right? 👍 / 👎 to inform future reviews.




This PR is an extraction of #19991
It basically exports
getTracingHeadersForFetchRequest, which was previously only exported for testing, but offers a great functionality if you want to add tracing headers to a request. I renamed it asaddTracingHeadersToFetchRequestsounded a little misleading, as it didn't really add headers to the request, as it returned the extracted headers from the request (or init, if there are any).Open question
I added
@hiddenand@internalto it, not sure if this is an approach we follow. I'm ok to remove it from the jsdoc